/**
    Copyright (c) 2010 yakiimo02
    Distributed under the New BSD License.
    See included license.txt or http://www.yakiimo3d.com/NewBSDLicense.txt
**/

#pragma once

#include "StoreFragments.h"
#include "SortFragmentsAndRender.h"

/**
    @brief
    @author yakiimo02
    @date   2010/6/20
**/
struct FragmentData
{
    unsigned int nColor;                // Pixel color
    unsigned int nDepthAndCoverage;        // Depth + coverage
};

/**
    @brief
    @author yakiimo02
    @date   2010/6/20
**/
struct FragmentLink
{
    FragmentData fragmentData;    // Fragment data
    unsigned int nNext;            // Link to next fragment
};

class SceneBase;

enum BlendMode 
{
    BLEND_REGULAR,                // use regular alpha blending
    BLEND_OIT                    // use OIT
};

/**
    @brief    Manages LinkedList OIT.
            LinkedList OIT consists of a StoreFragments step followed by a SortFragmentsAndRender step.
    @author yakiimo02
    @date   2010/6/20
**/
class LinkedListOIT
{
protected:
    struct PS_CB
    {
        UINT nFrameWidth;
        UINT nFrameHeight;
        UINT nReserved0;
        UINT nReserved1;
    };    

public:
    LinkedListOIT();
    ~LinkedListOIT();

    HRESULT OnCreateDevice( ID3D11Device* pDevice );
    HRESULT OnResizedSwapChain( const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, ID3D11Device* pDevice );
    void    OnReleasingSwapChain();
    void    OnDestroyDevice();
    void    OnRender( ID3D11DeviceContext* pD3DContext, ID3D11Device* pDevice, const DXGI_SURFACE_DESC* pBackBufferDesc, SceneBase* pScene, 
                      D3DXMATRIXA16* pmViewProj, const D3DXVECTOR3* pvCamEyePos, ID3D11RenderTargetView* pRTV, ID3D11DepthStencilView* pDSV );

    inline void         SetBlendMode( BlendMode blendMode ) { m_blendMode = blendMode; }
    inline BlendMode GetBlendMode() const { return m_blendMode;    }

protected:
    HRESULT CreateFragmentLink( const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, ID3D11Device* pDevice );
    HRESULT CreateStartOffset( const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, ID3D11Device* pDevice );

protected:
    // Fragment And Link
    ID3D11Buffer*                m_pFragmentLink;                // structured buffer
    ID3D11ShaderResourceView*   m_pFragmentLinkSRV;                // srv
    ID3D11UnorderedAccessView*    m_pFragmentLinkUAV;                // uav

    // Start Offset
    ID3D11Buffer*                m_pStartOffsetBuffer;            // structured buffer
    ID3D11ShaderResourceView*   m_pStartOffsetSRV;                // srv
    ID3D11UnorderedAccessView*    m_pStartOffsetUAV;                // uav

    // Shaders
    ID3D11PixelShader*            m_pDebugPS;                        // debug pixel shader

    // States
    ID3D11DepthStencilState*    m_pDepthStencilState;            // depth stencil state
    ID3D11RasterizerState*        m_pRS;                            // rasterizer state
    ID3D11RasterizerState*        m_pDebugRS;                        // debug rasterizer state
    ID3D11BlendState*            m_pAlphaBlendBS;                // alpha blending blend state

    // Constant Buffers
    ID3D11Buffer*               m_pPS_CB;                        // pixel shader constant buffer

    StoreFragments                m_storeFragments;                // store fragments into a linked list
    SortFragmentsAndRender        m_sortFragmentsAndRender;        // sort linked list and render

    BlendMode                    m_blendMode;                    // OIT or regular alpha blending.
};

extern LinkedListOIT g_linkedListOIT;